package sfsoftware.game.trevor;

import sfsoftware.game.TrevorLegacy;
import sfsoftware.game.actor.attributes.*;
import sfsoftware.game.actor.item.Item;
import sfsoftware.util.Actor;
import sfsoftware.util.Clock;
import sfsoftware.util.Sound;
import sfsoftware.util.Tile;
import sfsoftware.util.graphics.FloatingText;
import sfsoftware.util.graphics.Graphics;
import sfsoftware.util.graphics.RGBA;

public class Enemy extends Actor implements Explodable, Wiffable {	
	private boolean invulnerable = false;
	protected boolean invulnerabilityDraw = false;	
	private int invulnerabilityCoolDown = 0;
	private Clock invulnerabilityTimer = new Clock(500);
	
	private Clock deathBlinkTimer = new Clock(100);	
	private float deathBloat = 1.10f;
	
	public static final int DOWN_DIRECTION = 0;
	public static final int UP_DIRECTION = 1;
	public static final int LEFT_DIRECTION = 2;
	public static final int RIGHT_DIRECTION = 3;
	
	protected float weight = 1;
	protected int direction = 0;	
	protected Tile[][] tileMap;
	
	private int pain = 20;
	
	public Enemy(int destX, int destY, String texture, int destWidth, int destHeight) {
		super(destX, destY, texture, destWidth, destHeight);
		setFriction(0.05f);
	}
	
	public Enemy(int destX, int destY, String texture, int srcX, int srcY, int destWidth, int destHeight) {
		super(destX, destY, texture, srcX, srcY, destWidth, destHeight);
		setFriction(0.05f);
	}
	
	@Override
	public void collisionResult(Collidable object) {
		if(object.equals(TrevorLegacy.player))
		{
			if(health > 0 && !(isInvulnerable()))
			{				
				// Player should take damage here.
				// Default "pain" value is 20!
				Player.hurt(pain);
			}
		}
		
		super.collisionResult(object);
	}
	
	protected int distanceToPlayer()
	{
		return distanceToActor(TrevorLegacy.player);
	}
	
	public void draw(int width, int height, int srcX, int srcY, int srcWidth, int srcHeight, float red, float green, float blue, float alpha)
	{
		// Accelerating!
		if(getAcceleration() != 0)
		{
			accelerate();
		}
		
		if(deathBlinkTimer.updateClock() && health <= 0)
		{
			invulnerabilityDraw = !invulnerabilityDraw;
		}
		
		if(invulnerabilityTimer.updateClock() && invulnerable)
		{
			invulnerabilityCoolDown++;
			// Enemy cooldown for invulnerability should be shorter than the player's... and it is!
			if(invulnerabilityCoolDown > 2)
			{	
				invulnerable = false;	
				invulnerabilityCoolDown = 0;
				
				if(health <= 0 )
				{
					Sound.playSound("kill");
					generateParticles(100, 1, 1, 1);
					remove(true);
				}				
			}
		}
		
		if(!invulnerable)
		{
			super.draw(width, height, srcX, srcY, srcWidth, srcHeight, red, green, blue, alpha);
		}
		else if(health <= 0)
		{						
			if(invulnerabilityDraw)
			{			
				int newX = (int) ((getX() + (getWidth() / 2)) - ((getWidth() * deathBloat) / 2));
				int newY = (int) ((getY() + (getHeight() / 2)) - ((getHeight() * deathBloat) / 2));				
				int newWidth = (int) (getWidth() * deathBloat);
				int newHeight = (int) (getHeight() * deathBloat);
				
				Graphics.drawSprite(newX, newY, getTexture(), newWidth, newHeight, getSrcX(), getSrcY(), getWidth(), getHeight(), 1, 0, 0, alpha);				
			}
			else
			{
				super.draw(width, height, srcX, srcY, srcWidth, srcHeight, red, green, blue, alpha);
			}												
		}
		else if(invulnerabilityDraw)
		{
			super.draw(width, height, srcX, srcY, srcWidth, srcHeight, red, green, blue, alpha);
			invulnerabilityDraw = !invulnerabilityDraw;
		}
		else
		{
			invulnerabilityDraw = !invulnerabilityDraw;
		}
		
		if(Player.getInventory().contains("Book of Knowing") && health < maxHealth && health > 0)
		{
			RGBA borderColor = new RGBA(1, 1, 1, 0.6f);
			Graphics.drawRect(getX(), getY() - 9, getWidth(), 6, borderColor, 1);
			
			RGBA redTop = new RGBA(0.72f, 0, 0, 0.8f);
			RGBA redBottom = new RGBA(0.42f, 0, 0, 0.8f);
			Graphics.drawQuad(getX() + 1, getY() - 8, getWidth() - 2, 4, redTop, redTop, redBottom, redBottom);					

			RGBA greenTop = new RGBA(0, 0.72f, 0, 0.8f);
			RGBA greenBottom = new RGBA(0, 0.42f, 0, 0.8f);
			float lifeBarWidth = (((float)health / maxHealth) * (getWidth()- 2));
			Graphics.drawQuad(getX() + 1, getY() - 8, lifeBarWidth, 4, greenTop, greenTop, greenBottom, greenBottom);			
		}
		
	}
	
	@Override
	public void explode(Actor a) {
		if(!invulnerable)
		{
			// Bounce back!
			xDirection = Math.cos(getAngleFromActor(a)) * -1;
			yDirection = Math.sin(getAngleFromActor(a));
			
			setAcceleration(3.5f);
		}
		
		explode();
	}

	@Override
	public void explode() {
		hurt(5);
	}


	protected int getPain()
	{
		return pain;
	}
	
	private void hurt(int damage)
	{
		if(!invulnerable)
		{
			health = health - damage;
			invulnerable = true;
		}
	}

	protected boolean isInvulnerable()
	{
		return invulnerable;
	}	
	
	public boolean move(double dirX, double dirY, Tile[][] tileMap)
	{		
		boolean successfulMove = false;
		try
		{
			// Try to move!
			successfulMove = super.move(dirX, dirY, tileMap);
		}
		catch(ArrayIndexOutOfBoundsException e)
		{
			
		}
		return successfulMove;
	}	
	
	public void remove(boolean dropItem)
	{
		// Random item drops only occur if the enemy's health is at 0 when they are removed.
		if(dropItem)
		{
			int randomDrop = (int) (Math.random() * Math.max(2, (10 / Player.getLuck())));			
			// Random drop for hearts and money!	
			if(randomDrop == 0)		
			{		
				int itemX = (int) ((getX() + (getWidth() / 2)) - 8);
				int itemY = (int) ((getY() + (getHeight() / 2)) - 8);									
				Item.randomDropItem(itemX, itemY);					
			}			
			else if(randomDrop > 0)
			{
				// Really random drop... for the rarer goodies...
				randomDrop = (int) (Math.random() * (20 / Player.getLuck()));
				if(randomDrop == 0)		
				{		
					// Bomb...
					int itemX = (int) ((getX() + (getWidth() / 2)) - 20);
					int itemY = (int) ((getY() + (getHeight() / 2)) - 20);
					Item.randomRareDropItem(itemX, itemY);				
				}
				
			}
		}		
		
		super.remove();
	}
	
	protected void setPain(int p)
	{
		pain = p;
	}
	
	protected void updateCornerVariables(int x, int y, Tile[][] tileMap) throws ArrayIndexOutOfBoundsException
	{
		int upY = (int) Math.floor(((y - playingFieldY) - (height / 2)) / 40);
		int downY = (int) Math.floor((((y - playingFieldY) + (height / 2)) - 1) / 40);
		int leftX = (int) Math.floor(((x - playingFieldX) - (width / 2)) / 40);
		int rightX = (int) Math.floor((((x - playingFieldX)  + (width / 2)) - 1) / 40);
						
		topLeft = tileMap[leftX][upY].isWalkable();			
		bottomLeft = tileMap[leftX][downY].isWalkable();
		topRight = tileMap[rightX][upY].isWalkable();
		bottomRight = tileMap[rightX][downY].isWalkable();	
	}	
	
	@Override
	public void wiffaHit() {
		if(!invulnerable)
		{
			// Bounce back!
			xDirection = Math.cos(getAngleFromActor(TrevorLegacy.player)) * -1;
			yDirection = Math.sin(getAngleFromActor(TrevorLegacy.player));			

			// Calculate the bounce back based on size and "weight"
			float a  = (130 / ((getWidth() + getHeight()) / 2)) / weight;
			setAcceleration(a);
			
			// Chance of critical hit AKA double damage!
			int criticalChance = (int) (25 / Player.getLuck());				
			switch((int)(Math.random() * criticalChance))
			{
				case 0:
					hurt(Math.round(Player.getPlayer().getAttackDamage() * 2));
					new FloatingText((int)getX() + (getWidth() / 2), (int)getY(), "CRITICAL HIT!", 1, 1, 1, 0.95f);
					break;
				default:
					hurt(Math.round(Player.getPlayer().getAttackDamage()));
					new FloatingText((int)getX() + (getWidth() / 2), (int)getY(), "-" + (int) Math.round(Player.getPlayer().getAttackDamage()), 1, 1, 1, 0.95f);
					break;
			}
		}
	}
	
}
